﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QApplication>
#include <QRegularExpression>
#include <QFile>
#include <QTextStream>
#include <QIODevice>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QVariant>
#include <dialog.h>
#include <QStringList>
#include "QXlsx/xlsxrichstring.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // ui->spinBox->setMinimum(3);
    // ui->spinBox->setValue(3);

    // ui->groupBox_template->hide();
    // ui->label_regex->hide();
    // ui->lineEdit_regex->hide();

    ui->progressBar->setValue(0);

    QFile file1(DEFAULT_CONFIG_PATH);
    if (file1.exists()) {
        ui->lineEditConfig->setText(DEFAULT_CONFIG_PATH);
    }

    QFile file2(DEFAULT_TEMPLATE_PATH);
    if (file2.exists()) {
        ui->lineEditSAT->setText(DEFAULT_TEMPLATE_PATH);
    }

    ui->comboBox_config->addItems(cr.readFileKeys(ui->lineEditConfig->text()));
    ui->comboBox_config->setCurrentIndex(0);

    addComboboxItems(ui->comboBoxTmp, ui->lineEditSAT->text());

    setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);

    setFixedSize(this->size());

    // 设置 QProgressBar 样式表，使百分比显示在中间
    ui->progressBar->setStyleSheet(
        "QProgressBar {"
        "   border: 1px solid grey;"
        "   border-radius: 5px;"
        "   text-align: center;"  // 百分比文本居中
        "   font-size: 16px;"
        "}"
        "QProgressBar::chunk {"
        "   background-color: #05B8CC;"
        "   width: 20px;"
        "}"
        );

    QFileInfo fileInfo(QCoreApplication::applicationFilePath());
    QString datetime = fileInfo.lastModified().toString(u8"yyyy-MM-dd");

    setWindowTitle(QApplication::applicationName());


    ui->frame->setStyleSheet("background: transparent;");
    ui->frame->setAttribute(Qt::WA_TranslucentBackground);
    ui->label_rev->setStyleSheet("background: transparent;");
    ui->label_rev->setAttribute(Qt::WA_TranslucentBackground);
    ui->label_copyright->setStyleSheet("background: transparent;");
    ui->label_copyright->setAttribute(Qt::WA_TranslucentBackground);
    ui->frame->setFrameShape(QFrame::NoFrame);  // 移除边框

    ui->label_logo->setPixmap(QPixmap(":/icons/logo.ico").scaled(40,40));
    ui->label_logo->setAlignment(Qt::AlignRight);


    ui->label_rev->setText(QString(u8"版本 : ") + VERSION + u8" 日期 : " + datetime);
    ui->label_copyright->setText(QString(u8"CopyRight© ") + fileInfo.lastModified().toString(u8"yyyy") + u8"-2030" u8" 张钿");
    ui->label_title->setText(QApplication::applicationName());

    connect(ui->toolButtonConfig, &QToolButton::clicked, this, &MainWindow::toolButtonConfigSlots);
    connect(ui->toolButtonCase, &QToolButton::clicked, this, &MainWindow::toolButtonCaseSlots);
    connect(ui->toolButtonSAT, &QToolButton::clicked, this, &MainWindow::toolButtonSatSlots);
    connect(ui->pushButtonGenerate, &QToolButton::clicked, this, &MainWindow::pushButtonGenerateSlots);
    connect(ui->checkBox, &QCheckBox::toggled, this, &MainWindow::checkBoxToggledSlots);
    connect(ui->comboBox_config, &QComboBox::currentTextChanged, this, &MainWindow::configComboBoxChangedSlots);
}

MainWindow::~MainWindow()
{
    delete ui;
}

QString MainWindow::dialogPopout(const QString& fileFormat)
{
    QFileDialog fdg;
    QString filePath;

    filePath = fdg.getOpenFileName(this, u8"请选择文件",
                                   QApplication::applicationDirPath(),
                                   fileFormat);

    return filePath;

}



bool MainWindow::createOutputFile()
{
    bool ret = true;
    QFileDialog dl;
    path = dl.getSaveFileName(this, u8"保存文件", QApplication::applicationDirPath(), u8"excel文件 (*.xlsx *.xls)");

    if(!path.isEmpty()){
        dst_workbook = workbook_new(path.toStdString().c_str());
        if(dst_workbook) {

            if(ui->checkBox_header_footer->isChecked()) {

                Dialog dialog(logo_path, lFooter, rFooter);

                // QString lineStr;
                // QChar ch("_");
                // for(auto i = 0; i < LINE_CHAR_NUMBER; ++i) {
                //     lineStr+=ch;
                // }

                if(dialog.exec() == QDialog::Accepted) {
                    footer = dialog.getFooter();
                    logo_path = dialog.getImagePath();
                    font_setting = dialog.getFontSetting();
                    lFooter = dialog.getLFooter();
                    rFooter = dialog.getRFooter();
                } else {
                    dst_workbook = nullptr;
                    ret = false;
                }
            }

        }
    } else {
        ret = false;
    }



    return ret;
}

lxw_worksheet* MainWindow::createSheetByName(const char* sheetName)
{
    return workbook_add_worksheet(dst_workbook, sheetName);
}

void MainWindow::setSheetFormat(const QString& header)
{
    worksheet_set_margins(dst_worksheet, HEADER_LEFT_MARGIN, HEADER_RIGHT_MARGIN, HEADER_TOP_MARGIN, HEADER_BOTTOM_MARGIN);

    if(ui->checkBox_header_footer->isChecked()) {
        std::string str = logo_path.toStdString();
        options.image_center = str.c_str();

        worksheet_set_header_opt(dst_worksheet, header.toStdString().c_str(), &options);

        worksheet_set_footer(dst_worksheet, footer.toStdString().c_str());
    }
}

void MainWindow::copyHeaderFromTemplate()
{
    if(!tmpSht) {
        qDebug()<< "The pointer point to template sheet is null" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    if(!dst_worksheet){
        qDebug()<< "The pointer point to destination sheet is null:" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    int totalCol = tmpSht->dimension().columnCount();

    QJsonObject cfg = cr.getGenerateFileTemplateConfig();
    int startTestStepRow = cfg[TEST_STEP_START_LINE_KEY].toInt() - 1;   // libxlsxwriter库起始行为0, QXlsx库起始行为1

    // 复制列宽
    for (int col = 1; col <= totalCol; ++col) {
        copyColWidth(col);
    }

    // 遍历源工作表的单元格（测试步骤前的内容，包含测试步骤）
    for (int row = 1; row <= startTestStepRow; ++row) {
        for (int col = 1; col <= totalCol; ++col) {
            // 复制源表格的部分格式
            QXlsx::Format srcFormat = tmpSht->cellAt(row, col)->format();
            lxw_format* format = workbook_add_format(dst_workbook);
            formatCopy(srcFormat, format);

            // 写入新工作表
            worksheet_write_blank(dst_worksheet, row - 1, col - 1, format);
        }
        copyRowHeight(row);
    }
}

void MainWindow::formatCopy(const QXlsx::Format& src, lxw_format *dst)
{
    // copy font bold
    if(src.fontBold()) format_set_bold(dst);

    // copy font name
    format_set_font_name(dst, src.fontName().toStdString().c_str());

    // copy font color
    format_set_font_color(dst, src.fontColor().toRgb().value());

    // copy font size
    format_set_font_size(dst, src.fontSize());

    // copy text wraper
    if(src.textWrap()) format_set_text_wrap(dst);

    // copy horizontal alignment
    switch(src.horizontalAlignment()) {
    case QXlsx::Format::AlignHGeneral:
        break;
    case QXlsx::Format::AlignLeft:
        format_set_align(dst, LXW_ALIGN_LEFT);
        break;
    case QXlsx::Format::AlignHCenter:
        format_set_align(dst, LXW_ALIGN_CENTER);
        break;
    case QXlsx::Format::AlignRight:
        format_set_align(dst, LXW_ALIGN_RIGHT);
        break;
    case QXlsx::Format::AlignHFill:
        format_set_align(dst, LXW_ALIGN_FILL);
        break;
    case QXlsx::Format::AlignHJustify:
        format_set_align(dst, LXW_ALIGN_JUSTIFY);
        break;
    case QXlsx::Format::AlignHMerge:
        break;
    case QXlsx::Format::AlignHDistributed:
        format_set_align(dst, LXW_ALIGN_DISTRIBUTED);
        break;
    default:
        break;
    }

    // copy vertical alignment
    switch(src.verticalAlignment()) {
    case QXlsx::Format::AlignTop:
        format_set_align(dst, LXW_ALIGN_VERTICAL_TOP);
        break;
    case QXlsx::Format::AlignVCenter:
        format_set_align(dst, LXW_ALIGN_VERTICAL_CENTER);
        break;
    case QXlsx::Format::AlignBottom:
        format_set_align(dst, LXW_ALIGN_VERTICAL_BOTTOM);
        break;
    case QXlsx::Format::AlignVJustify:
        format_set_align(dst, LXW_ALIGN_VERTICAL_JUSTIFY);
        break;
    case QXlsx::Format::AlignVDistributed:
        format_set_align(dst, LXW_ALIGN_VERTICAL_DISTRIBUTED);
        break;
    default:
        break;
    }

    // copy border style
    switch(src.topBorderStyle()){
    case QXlsx::Format::BorderThin:
        format_set_top(dst, LXW_BORDER_THIN);
        break;
    case QXlsx::Format::BorderMedium:
        format_set_top(dst, LXW_BORDER_MEDIUM);
        break;
    case QXlsx::Format::BorderDashed:
        format_set_top(dst, LXW_BORDER_DASHED);
        break;
    case QXlsx::Format::BorderDotted:
        format_set_top(dst, LXW_BORDER_DOTTED);
        break;
    case QXlsx::Format::BorderThick:
        format_set_top(dst, LXW_BORDER_THICK);
        break;
    case QXlsx::Format::BorderDouble:
        format_set_top(dst, LXW_BORDER_DOUBLE);
        break;
    case QXlsx::Format::BorderHair:
        format_set_top(dst, LXW_BORDER_HAIR);
        break;
    case QXlsx::Format::BorderMediumDashed:
        format_set_top(dst, LXW_BORDER_MEDIUM_DASHED);
        break;
    case QXlsx::Format::BorderDashDot:
        format_set_top(dst, LXW_BORDER_DASH_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDot:
        format_set_top(dst, LXW_BORDER_MEDIUM_DASH_DOT);
        break;
    case QXlsx::Format::BorderDashDotDot:
        format_set_top(dst, LXW_BORDER_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDotDot:
        format_set_top(dst, LXW_BORDER_MEDIUM_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderSlantDashDot:
        format_set_top(dst, LXW_BORDER_SLANT_DASH_DOT);
        break;
    default:
        break;
    }

    switch(src.bottomBorderStyle()){
    case QXlsx::Format::BorderThin:
        format_set_bottom(dst, LXW_BORDER_THIN);
        break;
    case QXlsx::Format::BorderMedium:
        format_set_bottom(dst, LXW_BORDER_MEDIUM);
        break;
    case QXlsx::Format::BorderDashed:
        format_set_bottom(dst, LXW_BORDER_DASHED);
        break;
    case QXlsx::Format::BorderDotted:
        format_set_bottom(dst, LXW_BORDER_DOTTED);
        break;
    case QXlsx::Format::BorderThick:
        format_set_bottom(dst, LXW_BORDER_THICK);
        break;
    case QXlsx::Format::BorderDouble:
        format_set_bottom(dst, LXW_BORDER_DOUBLE);
        break;
    case QXlsx::Format::BorderHair:
        format_set_bottom(dst, LXW_BORDER_HAIR);
        break;
    case QXlsx::Format::BorderMediumDashed:
        format_set_bottom(dst, LXW_BORDER_MEDIUM_DASHED);
        break;
    case QXlsx::Format::BorderDashDot:
        format_set_bottom(dst, LXW_BORDER_DASH_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDot:
        format_set_bottom(dst, LXW_BORDER_MEDIUM_DASH_DOT);
        break;
    case QXlsx::Format::BorderDashDotDot:
        format_set_bottom(dst, LXW_BORDER_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDotDot:
        format_set_bottom(dst, LXW_BORDER_MEDIUM_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderSlantDashDot:
        format_set_bottom(dst, LXW_BORDER_SLANT_DASH_DOT);
        break;
    default:
        break;
    }

    switch(src.leftBorderStyle()){
    case QXlsx::Format::BorderThin:
        format_set_left(dst, LXW_BORDER_THIN);
        break;
    case QXlsx::Format::BorderMedium:
        format_set_left(dst, LXW_BORDER_MEDIUM);
        break;
    case QXlsx::Format::BorderDashed:
        format_set_left(dst, LXW_BORDER_DASHED);
        break;
    case QXlsx::Format::BorderDotted:
        format_set_left(dst, LXW_BORDER_DOTTED);
        break;
    case QXlsx::Format::BorderThick:
        format_set_left(dst, LXW_BORDER_THICK);
        break;
    case QXlsx::Format::BorderDouble:
        format_set_left(dst, LXW_BORDER_DOUBLE);
        break;
    case QXlsx::Format::BorderHair:
        format_set_left(dst, LXW_BORDER_HAIR);
        break;
    case QXlsx::Format::BorderMediumDashed:
        format_set_left(dst, LXW_BORDER_MEDIUM_DASHED);
        break;
    case QXlsx::Format::BorderDashDot:
        format_set_left(dst, LXW_BORDER_DASH_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDot:
        format_set_left(dst, LXW_BORDER_MEDIUM_DASH_DOT);
        break;
    case QXlsx::Format::BorderDashDotDot:
        format_set_left(dst, LXW_BORDER_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDotDot:
        format_set_left(dst, LXW_BORDER_MEDIUM_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderSlantDashDot:
        format_set_left(dst, LXW_BORDER_SLANT_DASH_DOT);
        break;
    default:
        break;
    }

    switch(src.rightBorderStyle()){
    case QXlsx::Format::BorderThin:
        format_set_right(dst, LXW_BORDER_THIN);
        break;
    case QXlsx::Format::BorderMedium:
        format_set_right(dst, LXW_BORDER_MEDIUM);
        break;
    case QXlsx::Format::BorderDashed:
        format_set_right(dst, LXW_BORDER_DASHED);
        break;
    case QXlsx::Format::BorderDotted:
        format_set_right(dst, LXW_BORDER_DOTTED);
        break;
    case QXlsx::Format::BorderThick:
        format_set_right(dst, LXW_BORDER_THICK);
        break;
    case QXlsx::Format::BorderDouble:
        format_set_right(dst, LXW_BORDER_DOUBLE);
        break;
    case QXlsx::Format::BorderHair:
        format_set_right(dst, LXW_BORDER_HAIR);
        break;
    case QXlsx::Format::BorderMediumDashed:
        format_set_right(dst, LXW_BORDER_MEDIUM_DASHED);
        break;
    case QXlsx::Format::BorderDashDot:
        format_set_right(dst, LXW_BORDER_DASH_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDot:
        format_set_right(dst, LXW_BORDER_MEDIUM_DASH_DOT);
        break;
    case QXlsx::Format::BorderDashDotDot:
        format_set_right(dst, LXW_BORDER_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderMediumDashDotDot:
        format_set_right(dst, LXW_BORDER_MEDIUM_DASH_DOT_DOT);
        break;
    case QXlsx::Format::BorderSlantDashDot:
        format_set_right(dst, LXW_BORDER_SLANT_DASH_DOT);
        break;
    default:
        break;
    }


}



void MainWindow::mergeCellsByTemplate(const int& start, const int& end, const int& offset, const bool& flag, const int& count)
{
    do {
        if(!tmpSht){
            qDebug()<< "The pointer point to tmpSht is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
            break;
        }
        if(!dst_worksheet){
            qDebug()<< "The pointer point to destination sheet is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
            break;
        }

        // 处理单元格合并
        QList<QXlsx::CellRange> mergedCells = tmpSht->mergedCells();
        foreach (const QXlsx::CellRange &mergedCell, mergedCells) {
            int firstRow = mergedCell.firstRow();
            int firstColumn = mergedCell.firstColumn();
            int lastRow = mergedCell.lastRow();
            int lastColumn = mergedCell.lastColumn();
            if (firstRow < start || firstRow > end) continue;

            if (flag) {
                if(firstRow == start) {
                    for(int n = 0; n < count; ++n) {
                        worksheet_merge_range(dst_worksheet, firstRow + n - 1, firstColumn - 1, lastRow + n - 1, lastColumn - 1, "", nullptr);
                    }
                }
            } else {
                worksheet_merge_range(dst_worksheet, firstRow + offset - 1, firstColumn - 1, lastRow + offset - 1, lastColumn - 1, "", nullptr);
            }

        }

    }while(0);

    return;
}



void MainWindow::writeHeaderContext(const int& srcSheetRow, const QString& caseName)
{
    Q_UNUSED(caseName)      // 不再检查版本格式，也就不需要记录版本格式不符的用例名称
    if(!tmpSht) {
        qDebug()<< "The pointer point to template sheet is null" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    if(!dst_worksheet){
        qDebug()<< "The pointer point to destination sheet is null:" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    int totalRow = tmpSht->dimension().rowCount();
    int totalCol = tmpSht->dimension().columnCount();

    QJsonArray colArr = cr.getInputSpecialProcessConfig(PROCESS_VERSION_KEY);
    QVariantList verColList = colArr.toVariantList();
    QJsonArray tArr = cr.getInputSpecialProcessConfig(PROCESS_SUFFIX_KEY);
    QVariantList suffixColList = tArr.toVariantList();
    QJsonObject columnMapping = cr.getColumnMapping();
    QJsonArray tCheckArr = cr.getInputSpecialProcessConfig(PROCESS_CHECK_KEY);
    QVariantList checkColList = tCheckArr.toVariantList();

    QHash<QString, QJsonArray> columnMappingHash;
    for (auto it = columnMapping.begin(); it != columnMapping.end(); ++it) {
        columnMappingHash.insert(it.key(), it.value().toArray());
    }

    // 遍历模板工作表的单元格
    for(int row = 1; row <= totalRow; ++row) {
        for (int col = 1; col <= totalCol; ++col) {
            // 读取单元格数据
            QVariant cellValue = tmpSht->read(row, col);

            // 复制源表格的部分格式
            QXlsx::Format srcFormat = tmpSht->cellAt(row, col)->format();
            lxw_format* format = workbook_add_format(dst_workbook);
            formatCopy(srcFormat, format);

            QString cellValueStr(cellValue.toString());

            // 移除字符串最后的换行符
            if(!cellValueStr.isEmpty() && cellValueStr.back() == "\n") {
                cellValueStr.chop(1);
            }

            //  处理版本
            bool flag = false;
            for(auto const & each : std::as_const(verColList)) {
                QString key = QString::number(each.toInt());
                QJsonArray mapArray = columnMapping[key].toArray();
                if(row == mapArray[0].toInt() && col == mapArray[1].toInt()) {
                    // QString verStr = srcSht->read(srcSheetRow, each.toInt()).toString();
                    // if(!styleCheck(verStr, "'?0?\\d+")) versionErrorList.append(caseName);       // 版本不一定是0开头的，可能是2位数版本，此处不在检查
                    QString cellStr = QString("%1").arg(srcSht->read(srcSheetRow, each.toInt()).toUInt(), 2, 10 , QChar('0'));
                    worksheet_write_string(dst_worksheet, row - 1, col - 1, cellStr.toStdString().c_str(), format);
                    flag = true;
                }
            }

            // 处理后缀
            for(auto const & each : std::as_const(suffixColList)) {
                QString key = QString::number(each.toInt());
                QJsonArray mapArray = columnMapping[key].toArray();
                if(row == mapArray[0].toInt() && col == mapArray[1].toInt()) {
                    QString cellStr = QString("%1%2").arg(srcSht->read(srcSheetRow, each.toInt()).toString(), ui->lineEdit_suffix->text());
                    worksheet_write_string(dst_worksheet, row - 1, col - 1, cellStr.toStdString().c_str(), format);
                    flag = true;
                }
            }

            // 处理勾选
            for(auto const & each : std::as_const(checkColList)) {
                QString key = QString::number(each.toInt());
                if (columnMappingHash.contains(key)) {
                    QJsonArray mapArray = columnMappingHash[key];
                    if(row == mapArray[0].toInt() && col == mapArray[1].toInt()) {
                        QString cellStr = srcSht->read(srcSheetRow, each.toInt()).toString();
                        if(checkedByString(row, col, cellStr)) {
                            flag = true;
                        } else {
                            checkErrorList.append(QPair<int, int>(srcSheetRow, each.toInt()));
                        }
                    }
                }
            }

            // 写入新工作表
            if (!flag)  worksheet_write_string(dst_worksheet, row - 1, col - 1, cellValueStr.toStdString().c_str(), format);
        }
    }




}

void MainWindow::writeCaseInfoToIndexsheet(lxw_worksheet* const sheet, const int& readRow, const int& writeRow)
{
    lxw_format* format = workbook_add_format(dst_workbook);
    format_set_text_wrap(format);               // 设置自动换行
    format_set_font_size(format, 10);           // 设置10号字体
    format_set_border(format, LXW_BORDER_THIN); // 设置细边框
    format_set_font_name(format, u8"微软雅黑");
    format_set_font_color(format, LXW_COLOR_BLUE);

    QJsonObject cfgObj = cr.getIndexSheetConfig();


    int rCol = 1, wCol = 1;
    QString text;

    for (auto const& key : std::as_const(indexTitleList)) {
        rCol = cfgObj[key].toArray()[0].toInt();
        wCol = cfgObj[key].toArray()[1].toInt();
        text = srcSht->read(readRow, rCol).toString();

        if(wCol == 1) {
            text = "=HYPERLINK(\"#'" + text + "'!A1\", \"" + text + "\")";

            // 修改格式
            lxw_format* hyperlink_format = workbook_add_format(dst_workbook);
            format_set_font_color(hyperlink_format, LXW_COLOR_BLUE);
            format_set_text_wrap(hyperlink_format);               // 设置自动换行
            format_set_font_size(hyperlink_format, 10);           // 设置10号字体
            format_set_border(hyperlink_format, LXW_BORDER_THIN); // 设置细边框
            format_set_font_name(hyperlink_format, u8"微软雅黑");
            format_set_underline(hyperlink_format, LXW_UNDERLINE_SINGLE);
            worksheet_write_formula(sheet, writeRow - 1, wCol - 1, text.toStdString().c_str(), hyperlink_format);
        } else {

            if(wCol == 3) {
                text = QString("%1").arg(text.toUInt(), 2, 10, QChar('0'));
            }

            worksheet_write_string(sheet, writeRow - 1, wCol - 1, text.toStdString().c_str(), format);
        }
    }

    caseCount++;
}

void MainWindow::copyRowHeight(const int& srcRow)
{
    worksheet_set_row(dst_worksheet, srcRow - 1, tmpSht->rowHeight(srcRow), nullptr);
}

void MainWindow::copyColWidth(const int& srcCol)
{
    worksheet_set_column(dst_worksheet, srcCol - 1, srcCol - 1, tmpSht->columnWidth(srcCol), nullptr);
}

void MainWindow::writeContextByMapping(
    const int& srcRow,
    const int& stepStartRow,
    const QStringList& strList,
    const QList<int>& dst_col_arr,
    const QString& caseName
    )
{
    Q_UNUSED(caseName)

    QJsonObject cfgObj = cr.getColumnMapping();
    QStringList srcColArr = cfgObj.keys();          // 源表格的列编号列表

    // 使用QHash存储cfgObj以提高查找效率
    QHash<QString, QJsonArray> cfgObjHash;
    for (auto it = cfgObj.begin(); it != cfgObj.end(); ++it) {
        cfgObjHash.insert(it.key(), it.value().toArray());
    }

    // 获取特殊格式列
    QStringList spList = cr.getSpecialColList();

    int oriRowHeight = tmpSht->rowHeight(stepStartRow);  // 获取模板行高
    int maxRowHeight = oriRowHeight;  // 缓存最大行高，避免重复设置

    // 遍历原表格的列编号列表
    for(auto const &each : std::as_const(srcColArr)) {
        if(!spList.contains(each)) {
            int srcCol = each.toInt();
            QVariant srcVal = srcSht->read(srcRow, srcCol);
            if (cfgObjHash.contains(each)) {
                QJsonArray cfgArray = cfgObjHash[each];
                int dstRow = cfgArray[0].toInt();
                int dstCol = cfgArray[1].toInt();

                // 获取模板单元格的格式
                QXlsx::Format tmpFormat = tmpSht->cellAt(dstRow, dstCol)->format();
                lxw_format* format = workbook_add_format(dst_workbook);
                // 复制格式
                formatCopy(tmpFormat, format);

                // 计算并更新最大行高
                int rowHeight = calRowHeight(srcVal.toString(), dstRow, dstCol);
                if(rowHeight > maxRowHeight) {
                    maxRowHeight = rowHeight;
                }

                // 写入新工作表
                worksheet_write_string(dst_worksheet, dstRow - 1, dstCol - 1, srcVal.toString().toStdString().c_str(), format);
            }
        } else {

            // 比较处理, 此处为测试步骤
            writeTestStepAndResult(stepStartRow, strList, dst_col_arr);

        }

    }

    // 循环结束后统一设置行高，避免重复计算
    if(maxRowHeight > oriRowHeight) {
        worksheet_set_row(dst_worksheet, stepStartRow - 1, maxRowHeight, nullptr);
    }

}

int MainWindow::calRowHeight(const QString& str, const int& tmpRow, const int& tmpCol)
{
    // 获取模板单元格的字体格式
    QXlsx::Format tmpFormat = tmpSht->cellAt(tmpRow, tmpCol)->format();
    tmpFormat.fontSize();
    // 计算该字体的高度
    QFontMetrics fontMetrics(tmpFormat.font());
    int fontHeight = fontMetrics.height();


    QList<QXlsx::CellRange> mergedCells = tmpSht->mergedCells();
    double colWidth = 0.0f;
    foreach (const QXlsx::CellRange &mergedCell, mergedCells) {
        int firstRow = mergedCell.firstRow();
        int firstColumn = mergedCell.firstColumn();
        int lastColumn = mergedCell.lastColumn();
        if (firstRow == tmpRow && firstColumn == tmpCol) {
            for(int col = firstColumn; col <= lastColumn; ++col) {
                colWidth += tmpSht->columnWidth(col);
            }
            break;
        }
    }

    // 获取文本的行数
    QStringList strList = str.split(u8"\n");

    // 遍历每一行文本，并根据字体及每一行的字数计算是否超出列宽，超出列宽则行数增加1行
    int lineCount = 0;
    for(auto const &str : std::as_const(strList)) {
        // 计算该行文本在单元格中占据几行
        double strWidth = fontMetrics.horizontalAdvance(str);
        lineCount += (strWidth / colWidth / 7.0f) + 1;          // 列宽转像素： 列宽 * 7.0
    }


    // 返回文本的高度, 增加1行作为余量
    // return (lineCount + 1) * fontHeight;
    return lineCount * fontHeight;
}

void MainWindow::writeTestStepAndResult(const int& stepStartRow, const QStringList& strList, const QList<int>& dst_col_arr)
{
    if(!dst_worksheet){
        qDebug()<< "ptr sheet is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    // 获取测试步骤编号所在的列号
    int seqNum = (dst_col_arr[0] < dst_col_arr[1] ? dst_col_arr[0] : dst_col_arr[1]) - 1;

    // 获取模板单元格的格式
    QXlsx::Format format1 = tmpSht->cellAt(stepStartRow, seqNum)->format();
    QXlsx::Format format2 = tmpSht->cellAt(stepStartRow, dst_col_arr[0])->format();
    QXlsx::Format format3 = tmpSht->cellAt(stepStartRow, dst_col_arr[1])->format();

    QStringList list_step = clearText(strList[0]);
    QStringList list_result = clearText(strList[1]);

    // 获取模板单元格的字体格式
    QXlsx::Format tmpFormat = tmpSht->cellAt(stepStartRow, dst_col_arr[0])->format();
    tmpFormat.fontSize();
    // 计算该字体的高度
    QFontMetrics fontMetrics(tmpFormat.font());
    int fontHeight = fontMetrics.height();

    int maxCharCount = cr.getCharactorCountPerLine();      // 获取单行最大的字符数

    for(int rowCount = 0; rowCount < (list_step.length() >= list_result.length() ? list_step.length() : list_result.length()); ++rowCount){
        // 计算并设置行高
        QString step_str = list_step[rowCount];
        QString result_str = list_result[rowCount];


        int row_height1 = (step_str.length() / maxCharCount + 1) * fontHeight;
        int row_height2 = (result_str.length() / maxCharCount + 1) * fontHeight;
        int row_height = row_height1 > row_height2 ? row_height1 : row_height2;
        worksheet_set_row(dst_worksheet, stepStartRow + rowCount - 1, row_height, nullptr);


        // 从模板中复制一行单元格格式
        for(int col = 1; col <= tmpSht->dimension().columnCount(); ++col){
            QVariant cellValue = tmpSht->read(stepStartRow, col);
            QXlsx::Format format = tmpSht->cellAt(stepStartRow, col)->format();
            lxw_format* format_new = workbook_add_format(dst_workbook);
            formatCopy(format, format_new);
            worksheet_write_string(dst_worksheet, stepStartRow + rowCount - 1, col - 1, cellValue.toString().toStdString().c_str(), format_new);
        }
        // 写入测试步骤序号
        lxw_format* newformat1 = workbook_add_format(dst_workbook);
        formatCopy(format1, newformat1);
        worksheet_write_number(dst_worksheet, stepStartRow + rowCount - 1, seqNum - 1, rowCount + 1, newformat1);

        // 写入测试步骤
        lxw_format* newformat2 = workbook_add_format(dst_workbook);
        formatCopy(format2, newformat2);
        worksheet_write_string(dst_worksheet, stepStartRow + rowCount - 1, dst_col_arr[0] - 1, step_str.toStdString().c_str(), newformat2);

        // 写入期望结果
        lxw_format* newformat3 = workbook_add_format(dst_workbook);
        formatCopy(format3, newformat3);
        worksheet_write_string(dst_worksheet, stepStartRow + rowCount - 1, dst_col_arr[1] - 1, result_str.toStdString().c_str(), newformat3);


    }
}

void MainWindow::copyTailContextFromTemplate(const int& srcStart, const int& srcEnd, const int& offset)
{
    if(!tmpSht) {
        qDebug()<< "The pointer point to template sheet is null" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    if(!dst_worksheet){
        qDebug()<< "The pointer point to destination sheet is null:" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    int totalCol = tmpSht->dimension().columnCount();

    // 遍历源工作表的单元格（测试步骤前的内容，包含测试步骤）
    for (int row = srcStart; row <= srcEnd; ++row) {
        int row_height = tmpSht->rowHeight(row);
        worksheet_set_row(dst_worksheet, row + offset - 1, row_height, nullptr);
        for (int col = 1; col <= totalCol; ++col) {
            // 读取单元格数据
            QVariant cellValue = tmpSht->read(row, col);

            // 复制源表格的部分格式
            QXlsx::Format srcFormat = tmpSht->cellAt(row, col)->format();
            lxw_format* format = workbook_add_format(dst_workbook);
            formatCopy(srcFormat, format);

            // 写入新工作表
            worksheet_write_string(dst_worksheet, row + offset -  1, col - 1, cellValue.toString().toStdString().c_str(), format);
        }
        // 行高设置
    }
}

bool MainWindow::checkedByString(const int& row, const int& col, QString str)
{
    bool res = true;
    do {
        if(!tmpSht){
            qDebug()<< "ptr satSheet is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
            break;
        }
        if(str.isEmpty()) {
            emptyTitleList.append(row);
            break;
        }

        QStringList valueList = str.split(CASE_SPLIT_CHAR);
        QString cellValue = tmpSht->read(row, col).toString();

        for (auto const & value : std::as_const(valueList)) {
            if (str.contains(u8"测试")) {
                if (value.contains(u8"测试")) {
                    str = value;
                } else {
                    str = value + u8"测试";
                }
            }

            if (!cellValue.contains(str)) {
                res = false;                
                break;
            } else {
            }
            cellValue.replace(CASE_CHECKBOX + str, "R" + str);
        }

        if (res) {
            QXlsx::Format format = tmpSht->cellAt(row, col)->format();
            lxw_format* format_new = workbook_add_format(dst_workbook);
            formatCopy(format, format_new);

            QStringList list = cellValue.split("R");


            QList<lxw_rich_string_tuple *> rich_string_list;

            QList<std::string> string_list; // 用于存储 std::string 对象

            string_list.reserve(1000);
            rich_string_list.reserve(1000);
            for(auto const &str : std::as_const(list)) {
                if (!str.isEmpty()) {
                    lxw_rich_string_tuple* fragment = new lxw_rich_string_tuple;
                    fragment->format = workbook_add_format(dst_workbook);
                    formatCopy(format, fragment->format);
                    string_list.append(str.toStdString()); // 将 std::string 添加到列表
                    fragment->string = string_list.last().c_str(); // 使用列表中字符串的指针
                    rich_string_list.append(fragment);
                }
                if(str != list.last()) {
                    lxw_rich_string_tuple* fragment = new lxw_rich_string_tuple;
                    fragment->format = workbook_add_format(dst_workbook);
                    formatCopy(format, fragment->format);
                    format_set_font_name(fragment->format, u8"Wingdings 2");
                    fragment->string = u8"R";
                    rich_string_list.append(fragment);
                }

            }

            const int listCount = rich_string_list.length();
            lxw_rich_string_tuple **rich_string = new lxw_rich_string_tuple*[listCount + 1];
            for(auto n = 0; n < listCount; n++) {
                rich_string[n] = rich_string_list.at(n);
            }
            rich_string[listCount] = nullptr;


            worksheet_write_rich_string(dst_worksheet, row - 1, col - 1, rich_string, format_new);

            // 释放内存
            if(rich_string){
                delete[] rich_string;
                rich_string = nullptr;
            }
        }

    }while(0);


    return res;
}



void MainWindow::writeTitleToIndexsheet(lxw_worksheet* const sheet, const int& writeRow)
{
    QJsonObject cfgObj = cr.getIndexSheetConfig();
    QStringList cfgArr = cfgObj.keys();

    lxw_format* format = workbook_add_format(dst_workbook);
    format_set_bold(format);
    format_set_border(format, LXW_BORDER_THIN); // 设置细边框
    format_set_font_name(format, u8"微软雅黑");

    if (!cfgArr.isEmpty()) {

        indexTitleList.clear();

        indexTitleList.reserve(100);
        while(indexTitleList.length() < cfgArr.length()){
            for (auto const& key : std::as_const(cfgArr)) {
                int tCol = cfgObj[key].toArray()[1].toInt();
                if (tCol == indexTitleList.length() + 1) indexTitleList.append(key);
            }
        }

        for (auto const &key : std::as_const(cfgArr)) {
            QJsonArray tCfg = cfgObj[key].toArray();
            int tColNum = tCfg[1].toInt();
            int tWidth = tCfg[2].toInt();
            if (tColNum) {
                worksheet_set_column(sheet, tColNum - 1, tColNum - 1, tWidth, nullptr);
                worksheet_write_string(sheet, writeRow, tColNum - 1, key.toStdString().c_str(), format);
            }
        }
    }
}




void MainWindow::writeCase()
{
    // 打开源文件
    QXlsx::Document srcDoc(ui->lineEditCase->text());
    QXlsx::Document templateDoc(ui->lineEditSAT->text());
    if(!createOutputFile()) return;

    QString lineStr;
    // QChar ch(0x203E);
    QChar ch('_');
    for(auto i = 0; i < LINE_CHAR_NUMBER; ++i) {
        lineStr+=ch;
    }


    // 获取模板表格
    tmpSht = (QXlsx::Worksheet*)templateDoc.sheet(ui->comboBoxTmp->currentText());
    // 获取用例源表格
    srcSht = (QXlsx::Worksheet*)srcDoc.sheet(ui->comboBox->currentText());

    // 获取用例过滤条件
    QJsonObject filterCondition = cr.getFilterCondition();
    QStringList filterKeys = filterCondition.keys();

    // 获取输入表格的单元格区域，并根据区域范围设置进度条范围
    int rowCount = srcSht->dimension().rowCount();
    ui->progressBar->setRange(0, rowCount);

    // 从配置文件中获取用例编号所在列号及起始步骤的行号
    QJsonObject cfg = cr.getGenerateFileTemplateConfig();
    int sheetNameCol = cfg[FILE_NAME_SOURCE_COLUMN_KEY].toInt();
    int startTestStepRow = cfg[TEST_STEP_START_LINE_KEY].toInt();   // libxlsxwriter库起始行为0, QXlsx库起始行为1
    int caseVerCol = cr.getInputSpecialProcessConfig(PROCESS_VERSION_KEY).at(0).toInt();             // 用例版本所在列

    // 索引表起始行
    int indexSheetRow = 1;

    // 从配置文件中获取需要比较，存放在2个数组中,
    QJsonObject columnMapping = cr.getColumnMapping();
    QStringList colKey = columnMapping.keys();
    QJsonArray cmpColArr = cr.getInputSpecialProcessConfig(PROCESS_COMPARE_KEY);

    QList<int> src_col_arr, dst_col_arr;
    src_col_arr.reserve(100);
    dst_col_arr.reserve(100);
    for (auto const & each : std::as_const(cmpColArr)) {
        int col = each.toInt();
        src_col_arr.append(col);
        QJsonArray tColArr = columnMapping[QString::number(col)].toArray();
        dst_col_arr.append(tColArr[1].toInt());
    }

    lxw_worksheet* indexSheet = createSheetByName(u8"索引表");
    writeTitleToIndexsheet(indexSheet, indexSheetRow++);


    for(int row = 1; row <= rowCount; ++row){
        // 读取用例编号
        QString caseNumberStr = srcSht->read(row, sheetNameCol).toString();
        QVariant caseVer = srcSht->read(row, caseVerCol);

        bool skipFlag = false;  // 用例跳过标志
        // 根据过滤条件判断测试用例是否需要跳过
        for(auto const & key : std::as_const(filterKeys)){
            if(srcSht->read(row, key.toInt()).toString().isEmpty()) {
                // emptyTitleList.append(row);
                skipFlag = true;
                break;
            }
            // 是否被过滤
            if(false == filterCondition[key].toArray().contains(srcSht->read(row, key.toInt()).toString())) {
                skipFlag = true;
                break;
            }
        }

        // 检查该行是否有空内容
        for (auto const& col: std::as_const(colKey)) {
            if(!skipFlag && !srcSht->cellAt(row, col.toInt())->value().isValid()) {
                emptyTitleList.append(row);
                skipFlag = true;
                break;
            }
        }

        // 判断用例编号是否为空
        if(caseNumberStr.isEmpty()) {
            ui->progressBar->setValue(row);
            ui->progressBar->update();
            skipFlag = true;
        }

        // 判断用例编号是否重复
        if(sheetList.contains(caseNumberStr)){
            duplicateList.append(row);
            ui->progressBar->setValue(row);
            ui->progressBar->update();
            skipFlag = true;
        }

        // 获取测试步骤
        QStringList strList;
        for (auto const& col: std::as_const(src_col_arr)) {
            QString tStr = srcSht->read(row, col).toString();
            strList.append(tStr);
        }

        int stepCounts = 1;         // 测试步骤统计
        if(!skipFlag && !checkStepAndResult(strList, caseNumberStr, stepCounts)) {
            skipFlag = true;
        }

        // 创建工作表
        if(!skipFlag) {
            dst_worksheet = createSheetByName(caseNumberStr.toStdString().c_str());
            if(!dst_worksheet) {
                qDebug()<< "ptr tmpSht is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
                faildList.append(QString::number(row));
                skipFlag = true;
            }
        }

        if(skipFlag){
            ui->progressBar->setValue(row);
            ui->progressBar->update();
            continue;
        }

        // 创建表格，并将模板中的表头拷贝到表格中
        copyHeaderFromTemplate();

        // 根据模板合并表格头部的单元格
        mergeCellsByTemplate(1, startTestStepRow -1, 0);

        // 拷贝头部内容
        writeHeaderContext(row, caseNumberStr);

        // 合并测试步骤单元格
        mergeCellsByTemplate(startTestStepRow, startTestStepRow, 0, true, stepCounts);

        // 写入内容
        writeContextByMapping(row, startTestStepRow, strList, dst_col_arr, caseNumberStr);

        // 合并表格尾部
        mergeCellsByTemplate(startTestStepRow + 1, tmpSht->dimension().rowCount(), stepCounts - 1);
        // 复制表格尾部内容
        copyTailContextFromTemplate(startTestStepRow + 1, tmpSht->dimension().rowCount(), stepCounts - 1);


        // 写入页眉页脚
        QString center = QString(u8"&C&[Picture]") \
                         /*+ u8"&8"*/ + font_setting + u8"\n"\
                         + u8R"(&"Calibri Light"&17)" + u8"&KAAAAAA" \
                         + lineStr;
        header = QString(u8"&L") + font_setting + "\n\n\n\n" + u8"用例编号: %1" + center + u8"&R" + font_setting + "\n\n\n\n" + u8"用例版本: %2";
        setSheetFormat(header.arg(caseNumberStr.toStdString().c_str(), QString("%1").arg(caseVer.toUInt(), 2, 10, QChar('0')).toStdString().c_str()));

        writeCaseInfoToIndexsheet(indexSheet, row, ++indexSheetRow);

        // 将成功创建的工作表放入用例表格列表
        sheetList.append(caseNumberStr);

        ui->progressBar->setValue(row);
        ui->progressBar->update();
    }


    lxw_format * format = workbook_add_format(dst_workbook);
    format_set_bold(format);
    format_set_font_size(format, 15);
    format_set_font_color(format, LXW_COLOR_RED);
    format_set_border(format, LXW_BORDER_NONE); // 设置无边框

    if (indexSheet) {
        QString info = QString(u8"共生成%1份测试用例表格").arg(caseCount);
        worksheet_merge_range(indexSheet, 0, 0, 0, indexTitleList.length() - 1, info.toStdString().c_str(), format);
        worksheet_set_row(indexSheet, 1, 30, nullptr);
    }
    // 保存文件
    saveOutputFile();


    // 创建一个 QFileInfo 对象，并传入文件路径
    QFileInfo fileInfo(path);

    // 使用 QFileInfo 的 path() 方法获取目录路径
    QString dirPath = fileInfo.path();

    QFileInfo fi(ui->lineEditCase->text());

    QString text;

    do {
        if( errorList.isEmpty()
            && versionErrorList.isEmpty()
            && titleErrorList.isEmpty()
            && prepareErrorList.isEmpty()
            && typeErrorList.isEmpty()
            && emptyTitleList.isEmpty()
            && faildList.isEmpty()
            && duplicateList.isEmpty()
            && checkErrorList.isEmpty()) {

            text += u8"所有测试用例已正确生成！";

            break;

        }

        if(caseCount == 0) {
            int count = 0;
            text += u8"无测试用例生成。\n\n";
            text += QString::number(++count) + u8".请检查输入文件和所选择的需要生成的表格是否正确！\n";
            text += QString::number(++count) + u8".如果输入文件和所选择的需要生成的表格，请根据错误日志：\"" + dirPath + u8"/error.txt\"" + u8"提示检查完成后重新生成！";
            break;
        }

        writeErrorCaseToFile(dirPath + u8"/error.txt");

        text += u8"根据输入文件《" + fi.fileName() + u8"》中表格\"" + ui->comboBox->currentText() + u8"\"  共生成" + QString::number(caseCount) + u8"份测试用例表格。\n\n";
        text += u8"部分测试用例存在错误，请根据错误日志：\"" + dirPath + u8"/error.txt\"" + u8"提示检查完成后重新生成！";

    } while(0);



    QMessageBox::information(this, u8"生成结果提示", text);

}




bool MainWindow::checkStepAndResult(const QStringList& compareList, const QString& caseNumber, int& stepCount)
{
    bool ret = true;

    int index = 0;

    for(auto const& str : std::as_const(compareList)) {
        QStringList tList = clearText(str);
        if (index++ == 0) stepCount = tList.length();
        else if (stepCount != tList.length()) {
            errorList.append(caseNumber);
            ret = false;
            break;
        }
    }

    return ret;
}





QStringList MainWindow::clearText(const QString& text)
{
    QStringList resList;
    resList.clear();

    QString regexStr = ui->lineEdit_regex->text();
    QRegularExpression regex(regexStr);

    QStringList list = text.split("\n");

    QString str;

    // 对每一行进行处理
    resList.reserve(1000);
    for(auto & line : std::as_const(list)){
        if(line.isEmpty()) continue;
        QRegularExpressionMatch matchRes = regex.match(line);
        // 符合正则表达式
        if(matchRes.hasMatch()){
            if(!str.isEmpty())resList.append(str);
            str.clear();
            str += matchRes.captured(1);
        } else if(!line.isEmpty()) {
            str += "\n" + line;
        }
    }

    if(!str.isEmpty()) resList.append(str);
    return resList;
}



void MainWindow::saveOutputFile()
{
    workbook_close(dst_workbook);
}



void MainWindow::writeErrorCaseToFile(const QString& filePath)
{
    if( errorList.isEmpty()
        && versionErrorList.isEmpty()
        && titleErrorList.isEmpty()
        && prepareErrorList.isEmpty()
        && typeErrorList.isEmpty()
        && emptyTitleList.isEmpty()
        && faildList.isEmpty()
        && duplicateList.isEmpty()
        && checkErrorList.isEmpty()) return;

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << !"错误日志文件打开失败";
        return;
    }

    QTextStream out(&file);
    // out.setCodec("UTF-8");

    if(!faildList.isEmpty()){
        out << QString(u8"输入表格以下所在行用例生成失败：").toUtf8() << "\n";
        for(auto const &str : std::as_const(faildList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!titleErrorList.isEmpty()){
        out << QString(u8"以下用例标题存在错误：").toUtf8() << "\n";
        for(auto const &str : std::as_const(titleErrorList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!prepareErrorList.isEmpty()){
        out << QString(u8"以下用例前提条件存在错误：").toUtf8() << "\n";
        for(auto const &str : std::as_const(prepareErrorList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!versionErrorList.isEmpty()){
        out << QString(u8"以下用例版本存在错误：").toUtf8() << "\n";
        for(auto const &str : std::as_const(versionErrorList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!typeErrorList.isEmpty()){
        out << QString(u8"以下用例试验类型写入错误：").toUtf8() << "\n";
        for(auto const &str : std::as_const(typeErrorList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!errorList.isEmpty()){
        out << QString(u8"以下用例测试步骤数量与期望结果数量不匹配：").toUtf8() << "\n";
        for(auto const &str : std::as_const(errorList)){
            // 将错误case写入错误记录表
            out << str << "\n";
        }
        out << "\n";
    }

    if(!emptyTitleList.isEmpty()){

        QSet<int> set(emptyTitleList.begin(), emptyTitleList.end());

        out << QString(u8"以下行号中的用例部分关键内容为空，请检查是否需要更新：").toUtf8() << "\n";

        QList<int> list(set.begin(), set.end());

        std::sort(list.begin(), list.end());
        for(auto const &value : std::as_const(list)){
            // 将错误case写入错误记录表
            out << QString::number(value) << "\n";
        }
        out << "\n";
    }

    if(!duplicateList.isEmpty()){

        QSet<int> set(duplicateList.begin(), duplicateList.end());

        out << QString(u8"以下行号中的用例编号与其他用例编号重复：").toUtf8() << "\n";

        QList<int> list(set.begin(), set.end());

        std::sort(list.begin(), list.end());
        for(auto const &value : std::as_const(list)){
            // 将错误case写入错误记录表
            out << QString::number(value) << "\n";
        }
    }

    if(!checkErrorList.isEmpty()){

        QSet<QPair<int, int>> set(checkErrorList.begin(), checkErrorList.end());

        out << QString(u8"输入表格的以下单元格内容不在模版包含范围：").toUtf8() << "\n";

        QList<QPair<int, int>> list(set.begin(), set.end());

        std::sort(list.begin(), list.end());
        for(auto const &value : std::as_const(list)){
            // 将错误case写入错误记录表
            out << u8"(" + QString::number(value.first) + u8"行," + QString::number(value.second) + u8"列)" << "\n";
        }
    }

    file.close();
}

// bool MainWindow::styleCheck(QString str, QString regexStr)
// {
//     static QRegularExpression regex(regexStr);
//     if(str.isEmpty()) return false;

//     regex.setPattern(regexStr);
//     QRegularExpressionMatch matchRes = regex.match(str);
//     matchRes = regex.match(str);

//     if(matchRes.hasMatch()) return true;
//     else return false;
// }





void MainWindow::addComboboxItems(QComboBox *comboBox, const QString& filePath, const int& defaultIndex)
{
    if(!comboBox){
        qDebug()<< "ptr comboBox is null :" << __FILE__ << ":" << Q_FUNC_INFO << ":"<<__LINE__;
        return;
    }

    QXlsx::Document doc(filePath);

    comboBox->clear();

    comboBox->addItems(doc.sheetNames());

    comboBox->setCurrentIndex(defaultIndex);

    comboBox->update();
}

// QXlsx::Worksheet *MainWindow::createIndexSheet(QXlsx::Document *doc, QString sheetName, QXlsx::Format format)
// {
//     QXlsx::Worksheet* sheet = nullptr;
//     QJsonObject cfgObj = cr.getIndexSheetConfig();
//     QStringList cfgArr = cfgObj.keys();

//     if (!cfgArr.isEmpty()) {

//         doc->addSheet(sheetName);
//         sheet = (QXlsx::Worksheet*)doc->sheet(sheetName);


//         indexTitleList.clear();


//         while(indexTitleList.length() < cfgArr.length()){
//             for (auto const& key : std::as_const(cfgArr)) {
//                 int tCol = cfgObj[key].toArray()[1].toInt();
//                 if (tCol == indexTitleList.length() + 1) indexTitleList.append(key);
//             }
//         }

//         for (auto const &key : std::as_const(cfgArr)) {
//             QJsonArray tCfg = cfgObj[key].toArray();
//             int tColNum = tCfg[1].toInt();
//             int tWidth = tCfg[2].toInt();
//             if (tColNum) {
//                 sheet->setColumnWidth(tColNum, tColNum, tWidth);
//                 sheet->write(2, tColNum, key, format);
//             }
//         }
//     }

//     return sheet;
// }




// void MainWindow::createHyperLink(QXlsx::Document *excel, QXlsx::Worksheet *srcSht, int readRow, int writeRow, QString caseName)
// {
//     QXlsx::Worksheet* sheet = (QXlsx::Worksheet*)excel->sheet(u8"索引表");

//     QXlsx::Format format;
//     format.setTextWrap(true);
//     format.setFontSize(10);
//     format.setBorderStyle(QXlsx::Format::BorderThin); // 设置细边框

//     QJsonObject cfgObj = cr.getIndexSheetConfig();

//     excel->selectSheet(caseName);

//     int rCol = 1, wCol = 1;
//     QString text;
//     for (auto const& key : std::as_const(indexTitleList)) {
//         rCol = cfgObj[key].toArray()[0].toInt();
//         wCol = cfgObj[key].toArray()[1].toInt();
//         text = srcSht->read(readRow, rCol).toString();

//         // 设置格式
//         format.setFontUnderline(QXlsx::Format::FontUnderlineNone);
//         format.setBorderColor(Qt::black);                 // 设置边框颜色为黑色

//         if(wCol == 1) {
//             text = "=HYPERLINK(\"#'" + text + "'!A1\", \"" + text + "\")";

//             // 修改格式
//             format.setFontColor(Qt::blue);
//             format.setFontUnderline(QXlsx::Format::FontUnderlineSingle);
//         }

//         if(wCol == 3) {
//             text = QString("%1").arg(text.toUInt(), 2, 10, QChar('0'));
//         }

//         sheet->write(writeRow, wCol, text, format);
//     }

//     caseCount++;

// }


void MainWindow::toolButtonConfigSlots()
{
    QString filePath = dialogPopout(u8"配置文件 (*.json)");
    if(filePath.isEmpty()) return;
    ui->lineEditConfig->setText(filePath);

    ui->comboBox_config->clear();
    ui->comboBox_config->addItems(cr.readFileKeys(ui->lineEditConfig->text()));
    ui->comboBox_config->setCurrentIndex(0);
}

void MainWindow::toolButtonCaseSlots()
{
    QString filePath = dialogPopout(u8"excel文件 (*.xlsx *.xls *.xlsm)");

    if(filePath.isEmpty()) return;
    ui->lineEditCase->setText(filePath);

    addComboboxItems(ui->comboBox, filePath);

}

void MainWindow::toolButtonSatSlots()
{
    QString filePath = dialogPopout(u8"excel文件 (*.xlsx *.xls *.xlsm)");
    if(filePath.isEmpty()) return;
    ui->lineEditSAT->setText(filePath);

    addComboboxItems(ui->comboBoxTmp, filePath);
}

void MainWindow::pushButtonGenerateSlots()
{
    cr.readConfigByKey(ui->comboBox_config->currentText());

    ui->progressBar->setValue(0);

    writeCase();

    errorList.clear();
    versionErrorList.clear();
    titleErrorList.clear();
    prepareErrorList.clear();
    typeErrorList.clear();
    emptyTitleList.clear();
    faildList.clear();
    indexTitleList.clear();
    duplicateList.clear();
    checkErrorList.clear();
    caseCount = 0;
    sheetList.clear();
    srcSht = nullptr;
    tmpSht = nullptr;
    dst_workbook = nullptr;
    dst_worksheet = nullptr;

}

void MainWindow::checkBoxToggledSlots()
{
    if(ui->checkBox->isChecked()){
        ui->toolButtonSAT->setEnabled(true);
        ui->lineEdit_suffix->setEnabled(true);
        ui->toolButtonConfig->setEnabled(true);
        ui->comboBoxTmp->setEnabled(true);
        ui->comboBox_config->clear();
        ui->comboBox_config->addItems(cr.readFileKeys(ui->lineEditConfig->text()));
        // disconnect(ui->comboBox_config, &QComboBox::currentTextChanged, this, &MainWindow::configComboBoxChangedSlots);
        return;
    }

    ui->toolButtonSAT->setDisabled(true);
    ui->lineEdit_suffix->setDisabled(true);
    ui->toolButtonConfig->setDisabled(true);
    ui->comboBoxTmp->setDisabled(true);

    // 改为默认的配置文件
    ui->lineEditConfig->setText(DEFAULT_CONFIG_PATH);
    ui->comboBox_config->clear();
    ui->comboBox_config->addItems(cr.readFileKeys(DEFAULT_CONFIG_PATH));
    // connect(ui->comboBox_config, &QComboBox::currentTextChanged, this, &MainWindow::configComboBoxChangedSlots);

}

void MainWindow::configComboBoxChangedSlots()
{
    if(ui->comboBox_config->count() > ui->comboBox_config->count()) return;

    ui->comboBoxTmp->setCurrentIndex(ui->comboBox_config->currentIndex());

}

